package coherence.multiarray;

import java.util.List;
import java.util.Vector;


public class RecursiveAccess {

	public static void main(String[] args) {
		
		int[] sizes = new int[]{2, 4, 5, 3, 7, 2};
		int[] indices = new int[]{2, -1, -1, 3, -1, 2};
		//MultiDimensionalArray multiDimensionalArray = new MultiDimensionalArray(sizes);
		printAll(indices, sizes);
		
	}
	
	/*
	class PopulationFunctor implements Functor{

		@Override
		public float getFloat() {
			// TODO Auto-generated method stub
			return 0;
		}
		
	}
	*/
	
	/*
	public void recurse(int[] indices, Functor functor){
		
	}
	*/
	
	//List<int[]> sectorList = new Vector<int[]>();
	
	//method to generate cartesian product of all unfixed indices in the indices array
	//the fixed indices have nonnegative values, and the non-fixed indices have 
	//value of negative one
	//the sizes array specifies the size of each attribute space, ie. the number
	//of values that attribute can take
	public static List<int[]> generateAllPermutations(int[] indices, int[] sizes){
		List<int[]> sectorList = new Vector<int[]>();
		int[] currentIndices = new int[indices.length];
		for(int i = 0; i < indices.length; i++){
			currentIndices[i] = indices[i];
		}
		//generate all permutations recursively starting at index zero and
		//working up.  The array length starts at its final size, but the 
		//initial values are don't cares and are over-written as we get to 
		//their level in the iteration
		//we do this since array concatenation is expensive in Java
		generateAllPermutations(indices, currentIndices, sizes, 0, sectorList);
		return sectorList;
	}
	
	//this is the recursive part of the algorithm
	//it uses the last argument as a global accumulator
	public static void generateAllPermutations(int[] indices, int[] currentIndices, int[] sizes, int indexNumber, List<int[]> output){
		if(indexNumber == sizes.length){
			output.add(currentIndices);
			return;
		} else if(indices[indexNumber] != -1){
			//this is a fixed index, so we do not expand on it, but just simply jump over it
			generateAllPermutations(indices, currentIndices, sizes, indexNumber + 1, output);
			return;
		}
		for(int i = 0; i < sizes[indexNumber]; i++){
			//this is a non-fixed index, so we expand on it for as many values as the correesponding
			//attribute can take
			int[] currentIndicesCopy = copyIntArray(currentIndices, i, indexNumber);
			generateAllPermutations(indices, currentIndicesCopy, sizes, indexNumber + 1, output);
		}
	}	
	
	public static void printAll(int[] indices, int[] sizes){
		int[] currentIndices = new int[indices.length];
		for(int i = 0; i < indices.length; i++){
			currentIndices[i] = indices[i];
		}
		printAll(indices, currentIndices, sizes, 0);
	}
	
	public static void printAll(int[] indices, int[] currentIndices, int[] sizes, int indexNumber){
		if(indexNumber == sizes.length){
			printIntArray(currentIndices);
			return;
		} else if(indices[indexNumber] != -1){
			printAll(indices, currentIndices, sizes, indexNumber + 1);
			return;
		}
		for(int i = 0; i < sizes[indexNumber]; i++){
			int[] currentIndicesCopy = copyIntArray(currentIndices, i, indexNumber);
			printAll(indices, currentIndicesCopy, sizes, indexNumber + 1);
		}
	}
	
	//utility class for copying an array while replacing one element with a new value
	//this is useful for generating cartesian products recursively while instantiating
	//one attribute value at a time, in this case in order of its place in the attribute array
	private static int[] copyIntArray(int[] currentIndices, int newInt, int index){
		int[] currentIndicesCopy = new int[currentIndices.length];
		for(int j = 0; j < currentIndices.length; j++)
			currentIndicesCopy[j] = currentIndices[j];
		currentIndicesCopy[index] = newInt;
		return currentIndicesCopy;
	}
	
	private static void printIntArray(int[] indices){
		StringBuffer arrayString = new StringBuffer("{");
		for(int i = 0; i < indices.length - 1; i++)
			arrayString.append(indices[i] + ", ");
		arrayString.append(indices[indices.length - 1] + " }");
		System.out.println(arrayString);
	}
	
}
/*
class MultiDimensionalArray{
	
	int[] sizes;
	
	public MultiDimensionalArray(int[] sizes){
		this.sizes = sizes;
	}
	
	public void setElement(int[] indices, Object o){
		
	}
	
	public Object getElement(int[] indices){
		return null;
	}
}

interface Functor{
	
	public float getFloat();
	
}
*/